/***********************************************************************
 * Module:  RotateCommand.java
 * Author:  Nikola
 * Purpose: Defines the Class RotateCommand
 ***********************************************************************/

package genedit.controller;

import genedit.model.graph.ConnectionPoint;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.view.graph.ElementPainter;

import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class RotateCommand extends Command {
	private double rotation;

	private Set<GraphElement> rotatedElements;
	private Point2D centerOfRotation;
	private double angle;
	private double globalAngle;
	private HashMap<GraphElement,HashMap<ConnectionPoint,Point2D>> connectionPointsBackup;
	public static HashMap<GraphElement,HashMap<ConnectionPoint,Point2D>> translateConnectionPoints=null;
	private boolean useGlobal;
	
	/** @param isUndoable */
	public RotateCommand(boolean isUndoable, double angle, double globalAngle) {
		super(isUndoable);
		this.angle = angle;
		this.globalAngle = globalAngle;
		this.useGlobal=false;
	}

	public double getRotation() {
		return rotation;
	}

	/** @param newRotation */
	public void setRotation(double newRotation) {
		rotation = newRotation;
	}

	public void execute() {
		if(!useGlobal&&translateConnectionPoints==null){
			//bacukp points
			translateConnectionPoints=new HashMap<GraphElement, HashMap<ConnectionPoint,Point2D>>();
			for(GraphElement element:rotatedElements){
				HashMap<ConnectionPoint,Point2D> points=new HashMap<ConnectionPoint, Point2D>();
				for(ConnectionPoint point:element.getConnectionPoints()){
					points.put(point, new Point2D.Double(point.getPosition().getX(),point.getPosition().getY()));
				}
				translateConnectionPoints.put(element, points);
			}
		}
		Iterator<GraphElement> iterator = getIteratorRotatedElements();
		// prodjemo kroz sve selektovane elemente koji nisu link i zarotiramo ih
		while (iterator.hasNext()) { 
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				ElementPainter currentPainter=getDocument().getPainter(current);
				current.setRotation(current.getRotation() + angle);
				currentPainter.refreshAffine();
			}		
		}
		
		iterator = getIteratorRotatedElements();
		// vratimo connection pointe unutar elemenata
		while (iterator.hasNext()) { 
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				ElementPainter currentPainter=getDocument().getPainter(current);
				for (ConnectionPoint cp : current.getConnectionPoints()){
					if(!currentPainter.isElementAt(cp.getPosition())){
						Point2D newPosition=new Point2D.Double(current.getPosition().getX()+current.getSize().getWidth()/2,
								current.getPosition().getY()+current.getSize().getHeight()/2);
						cp.setPosition(newPosition);
					}
				}
			}
		}
		
		iterator = getIteratorRotatedElements();
		// ispravi likove
		while (iterator.hasNext()) { 
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				for (ConnectionPoint cp : current.getConnectionPoints()){
					for(Link link1 : cp.getEnding()) {
						if(!rotatedElements.contains(getDocument().getPainter(link1))){
							link1.removeIntersectPoints();
							link1.addIntersectionPoints();
						}
					}
					for(Link link1 : cp.getStarting()) {
						if(!rotatedElements.contains(getDocument().getPainter(link1))){
							link1.removeIntersectPoints();
							link1.addIntersectionPoints();
						}
					}
				}
			}
		}
		
		//ako je kraj rotiranja ispravi veze
		if(undoable){
			if(!useGlobal){
				connectionPointsBackup=translateConnectionPoints;
			}
			translateConnectionPoints=null;
			for(GraphElement element : rotatedElements){
				if(!(element instanceof Link)) {
					for(ConnectionPoint point:element.getConnectionPoints()){
						for(Link link:point.getStarting()){
							link.removeIntersectPoints();
							link.rectLink();
							link.addIntersectionPoints();
						}
						for(Link link:point.getEnding()){
							link.removeIntersectPoints();
							link.rectLink();
							link.addIntersectionPoints();
						}
					}
				}
			}
		}
		
		getDocument().getModel().refresh();

	}

	public void undo() {
		//pri sledećem execute treba da se koristi globalAngle
		angle=globalAngle;
		useGlobal=true;
		
		Iterator<GraphElement> iterator = getIteratorRotatedElements();
		while (iterator.hasNext()) {
			GraphElement current = iterator.next();
			if (!(current instanceof Link)) {
				current.setRotation(current.getRotation() - globalAngle);
			}
			getDocument().getPainter(current).refreshAffine();
			getDocument().getModel().refresh();
		}

		//vraćanje starih veza
		for(GraphElement element:rotatedElements){
			HashMap<ConnectionPoint,Point2D> points=connectionPointsBackup.get(element);
			for(ConnectionPoint point:element.getConnectionPoints()){
				Point2D oldPosition=points.get(point);
				point.setPosition(new Point2D.Double(oldPosition.getX(),oldPosition.getY()));
			}
		}
		//ispravljanje veza
		for(GraphElement element : rotatedElements){
			if(!(element instanceof Link)) {
				for(ConnectionPoint point:element.getConnectionPoints()){
					for(Link link:point.getStarting()){
						link.removeIntersectPoints();
						link.rectLink();
						link.addIntersectionPoints();
					}
					for(Link link:point.getEnding()){
						link.removeIntersectPoints();
						link.rectLink();
						link.addIntersectionPoints();
					}
				}
			}
		}
	}

	/** @pdGenerated default getter */
	public Set<GraphElement> getRotatedElements() {
		if (rotatedElements == null)
			rotatedElements = new java.util.HashSet<GraphElement>();
		return rotatedElements;
	}

	/** @pdGenerated default iterator getter */
	public java.util.Iterator<GraphElement> getIteratorRotatedElements() {
		if (rotatedElements == null)
			rotatedElements = new java.util.HashSet<GraphElement>();
		return rotatedElements.iterator();
	}

	/**
	 * @pdGenerated default setter
	 * @param newMovedElements
	 */
	public void setRotatedElements(java.util.Collection<GraphElement> newMovedElements) {
		removeAllRotatedElements();
		for (java.util.Iterator<GraphElement> iter = newMovedElements.iterator(); iter.hasNext();)
			addRotatedElements((GraphElement) iter.next());
	}

	/**
	 * @pdGenerated default add
	 * @param newElementPainter
	 */
	public void addRotatedElements(GraphElement newElementPainter) {
		if (newElementPainter == null)
			return;
		if (this.rotatedElements == null)
			this.rotatedElements = new java.util.HashSet<GraphElement>();
		if (!this.rotatedElements.contains(newElementPainter))
			this.rotatedElements.add(newElementPainter);
	}

	/**
	 * @pdGenerated default remove
	 * @param oldElementPainter
	 */
	public void removeRotatedElements(GraphElement oldElementPainter) {
		if (oldElementPainter == null)
			return;
		if (this.rotatedElements != null)
			if (this.rotatedElements.contains(oldElementPainter))
				this.rotatedElements.remove(oldElementPainter);
	}

	/** @pdGenerated default removeAll */
	public void removeAllRotatedElements() {
		if (rotatedElements != null)
			rotatedElements.clear();
	}

	/** @pdGenerated default getter */
	public Point2D getCenterOfRotation() {
		return centerOfRotation;
	}

	/** @pdGenerated default setter */
	public void setCenterOfRotation(Point2D centerOfRotation) {
		this.centerOfRotation = centerOfRotation;
	}

}